/////////////////////////////////////////////////////////////////////////////////////
//
//
//
// Using the timer to interface with an Ultrasonic Rangefinder.
// After comms are established, an output pulse is generated, period of 1sec,
//  inverse duty cycle of 2ms. The falling edge of the PWM signal triggers the
//  rangefinder to start its measurement sequence.
// A second timer is configured as an input timer, measuring the pulse the
//  rangefinder returns. The distance to the object can be determined by the
//  width of the returned pulse and the speed of sound (~343.2m.s^-1)
//
//-----------------------------------------------------------------------------------
//
//
// The range is converted to a string using sprintf(). To use sprintf(), the stack
//  size must be increased in the linker settings. I've set this project to have a
//  stack size of 2048.
// After converting to a string, the range is sent across the UART.
//
/////////////////////////////////////////////////////////////////////////////////////


#include "inc/hw_types.h"
#include "inc/lm4f120h5qr.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"
#include "inc/hw_memmap.h"
#include <stdio.h>

//////////////////////////////////////////////////

#include "UART.h"
#include "T0.h"
#include "T1.h"
#include "T2.h"
#include "T3.h"
#include "T5.h"
#include "Timer_Interrupts.h"
#include "Range_Calculate.h"
//#include "Serial_Transmit.h"

//////////////////////////////////////////////////

#define U_SENSOR_1	1
#define U_SENSOR_2	2
#define U_SENSOR_3	3
#define U_SENSOR_4	4

volatile unsigned int RxBufferIndex;
volatile unsigned char RxBuffer[200];

volatile unsigned int rangeFinderIndex = 0;


volatile unsigned int T1ReceiveTS[20];
volatile unsigned int T2ReceiveTS[20];
volatile unsigned int T3ReceiveTS[20];
volatile unsigned int T0ReceiveTS[20];
volatile unsigned int T1ReceiveIndex;
volatile unsigned int T2ReceiveIndex;
volatile unsigned int T3ReceiveIndex;
volatile unsigned int T0ReceiveIndex;
volatile unsigned int T1PrevIndex;
volatile unsigned int T2PrevIndex;
volatile unsigned int T3PrevIndex;
volatile unsigned int T0PrevIndex;


void TIMER0_B_INT(void){
	unsigned long TimerStatus;

	// Get the interrupt status
	TimerStatus = WTIMER0_MIS_R;
	// Clear the asserted interrupts
	WTIMER0_ICR_R = TimerStatus;

	T0ReceiveTS[T0ReceiveIndex++] = WTIMER0_TBR_R;

	//toggle so we can see when the interrupt is being triggered in the Saleae Logic Analyser
	GPIO_PORTB_DATA_R |= GPIO_PIN_1;
	GPIO_PORTB_DATA_R &= !GPIO_PIN_1;
}


void TIMER1_B_INT(void){
	unsigned long TimerStatus;

	// Get the interrupt status
	TimerStatus = WTIMER1_MIS_R;
	// Clear the asserted interrupts
	WTIMER1_ICR_R = TimerStatus;

	T1ReceiveTS[T1ReceiveIndex++] = WTIMER1_TBR_R;

	//toggle so we can see when the interrupt is being triggered in the Saleae Logic Analyser
	GPIO_PORTB_DATA_R |= GPIO_PIN_1;
	GPIO_PORTB_DATA_R &= !GPIO_PIN_1;
}


void TIMER2_B_INT(void){
	unsigned long TimerStatus;

	// Get the interrupt status
	TimerStatus = WTIMER2_MIS_R;
	// Clear the asserted interrupts
	WTIMER2_ICR_R = TimerStatus;

	T2ReceiveTS[T2ReceiveIndex++] = WTIMER2_TBR_R;

	//toggle so we can see when the interrupt is being triggered in the Saleae Logic Analyser
	GPIO_PORTB_DATA_R |= GPIO_PIN_1;
	GPIO_PORTB_DATA_R &= !GPIO_PIN_1;
}


void TIMER3_B_INT(void){
	unsigned long TimerStatus;

	// Get the interrupt status
	TimerStatus = WTIMER3_MIS_R;
	// Clear the asserted interrupts
	WTIMER3_ICR_R = TimerStatus;

	T3ReceiveTS[T3ReceiveIndex++] = WTIMER3_TBR_R;

	//toggle so we can see when the interrupt is being triggered in the Saleae Logic Analyser
	GPIO_PORTB_DATA_R |= GPIO_PIN_1;
	GPIO_PORTB_DATA_R &= !GPIO_PIN_1;
}


/* UART5 Interrupt Handler */
void UART5_INT(void){

    unsigned long UART5_Status;

    //Get the interrupt status
    UART5_Status = UART5_MIS_R;

    //Clear the asserted interrupts
    UART5_ICR_R = UART5_Status;

    // While there are characters in the FIFO...
    while((~UART5_FR_R & UART_FR_RXFE))
    {

    	// Read the next character from the UART,
        RxBuffer[RxBufferIndex] = UART5_DR_R;

        // Write it back to the UART,
    	UART5_DR_R = RxBuffer[RxBufferIndex];

    	// Increment the buffer, unless a backspace was sent.
    	if (RxBuffer[RxBufferIndex] == 0x08){
    		if(RxBufferIndex > 0) RxBufferIndex--;
    	}
    	else RxBufferIndex++;

    }
}

void Interrupt_Enable(){
	// Sprinkle of in-line assembly to enable processor interrupts
	__asm("cpsie");
}


void debugPortSetup(){

	// Enable PORTB peripheral
	SYSCTL_RCGCGPIO_R |= SYSCTL_RCGCGPIO_R1;							//Add PORTB to enabled peripherals

	//Configure PORTB
	GPIO_PORTB_DIR_R |= GPIO_PIN_0|GPIO_PIN_1;							//Pins 0,1 output. Maintain other bits
	GPIO_PORTB_DEN_R |= GPIO_PIN_0|GPIO_PIN_1;							//Digital enable
	GPIO_PORTB_PDR_R |= GPIO_PIN_0|GPIO_PIN_1;							//Pull down

	GPIO_PORTB_DATA_R = 0;												//Initialise off
}


/* Main */
void main(void){


	debugPortSetup();

	// Setup the system clock - 40MHz
	SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ|SYSCTL_OSC_MAIN);



	UART0_Init();

//	UART5_Buffer_Init();
	UART5_Init();


	Timer0_Init();
	Timer1_Init();
	Timer2_Init();
	Timer3_Init();
	Timer5_Init();

	Interrupt_Enable();


	// Now we wait.
	while(1){

		if(T0ReceiveIndex > T0PrevIndex && T0PrevIndex < 6){
			Range(T0ReceiveTS[T0PrevIndex],T0ReceiveTS[0],U_SENSOR_1, T0PrevIndex);
			T0PrevIndex++;
		}
		if(T1ReceiveIndex > T1PrevIndex && T1PrevIndex < 6){
			Range(T1ReceiveTS[T1PrevIndex],T1ReceiveTS[0],U_SENSOR_2, T1PrevIndex);
			T1PrevIndex++;
		}
		if(T2ReceiveIndex > T2PrevIndex && T2PrevIndex < 6){
			Range(T2ReceiveTS[T2PrevIndex],T2ReceiveTS[0],U_SENSOR_3, T2PrevIndex);
			T2PrevIndex++;
		}
		if(T3ReceiveIndex > T3PrevIndex && T3PrevIndex < 6){
			Range(T3ReceiveTS[T3PrevIndex],T3ReceiveTS[0],U_SENSOR_4, T3PrevIndex);
			T3PrevIndex++;
		}
	}
}
